package edu.bbu.commonproject.backend.db.services.mongodb;

import java.util.ArrayList;

import com.mongodb.BasicDBObject;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MongoException;

import edu.bbu.commonproject.backend.db.exceptions.DataBaseErrorException;
import edu.bbu.commonproject.backend.db.exceptions.DirectoryConflictException;
import edu.bbu.commonproject.backend.db.exceptions.UserConflictException;
import edu.bbu.commonproject.backend.db.factory.mongodb.MongoDBDAOFactory;
import edu.bbu.commonproject.backend.db.model.DBDirectory;
import edu.bbu.commonproject.backend.db.services.DirectoryDAOServices;

/**
 * The MongoDB directory services.
 */
public class MongoDBDirectoryDAOService implements DirectoryDAOServices
{
	/**
	 * Createing a new directory.
	 */
	public void createDirectory(DBDirectory directory) throws DirectoryConflictException, DataBaseErrorException
	{
		if(isExistingDirectory(directory))
		{
			throw new DirectoryConflictException("Directory already exists.");
		}
		else 
		{
			try
			{
				BasicDBObject newDirectoryObject = new BasicDBObject();
				
				newDirectoryObject.put("parent", directory.getParentDirectory());
				newDirectoryObject.put("name", directory.getDirectoryName());
				
				MongoDBDAOFactory.dataBase.getCollection(directory.getOwner() + ".directories").insert(newDirectoryObject);
			}
			catch (MongoException e)
			{
				throw new DataBaseErrorException("Error occured on database, when creating a new directory.");
			}
		}
	}

	/**
	 * Deleting an existing directory.
	 */
	public void deleteDirectory(DBDirectory directory) throws DirectoryConflictException, DataBaseErrorException
	{
		if(!isExistingDirectory(directory))
		{
			throw new DirectoryConflictException("Directory already deleted.");
		}
		else
		{
			try
			{
				BasicDBObject directoryObject = new BasicDBObject();
				
				directoryObject.put("parent", directory.getParentDirectory());
				directoryObject.put("name", directory.getDirectoryName());
				
				MongoDBDAOFactory.dataBase.getCollection(directory.getOwner() + ".directories").remove(directoryObject);
			}
			catch (MongoException e)
			{
				throw new DataBaseErrorException("Error occured on database, when deleting a new directory.");
			}
		}
	}

	/**
	 * Getting the list of directories.
	 */
	public ArrayList<String> getDirectoriesFromDirectory(DBDirectory directory) throws DataBaseErrorException
	{
		try
		{
			BasicDBObject directoryObject = new BasicDBObject();
			directoryObject.put("parent", directory.getParentDirectory() + directory.getDirectoryName() + "\\");
			
			ArrayList<String> directoryList = new ArrayList<String>();
			DBCursor cursor = MongoDBDAOFactory.dataBase.getCollection(directory.getOwner() + ".directories").find(directoryObject);
			
			while(cursor.hasNext())
			{
				directoryList.add((String) cursor.next().get("name"));
			}
			
			return directoryList;
		}
		catch (MongoException e)
		{
			throw new DataBaseErrorException("Error occured on database, when getting the directory, directories content.");
		}
	}
	
	/**
	 * Getting the base directory.
	 */
	public DBDirectory getBaseDirectory(String owner)
	{
		DBDirectory baseDirectory = new DBDirectory();
		baseDirectory.setOwner(owner);
		baseDirectory.setDirectoryName("base");
		baseDirectory.setParentDirectory("\\");
		
		return baseDirectory;
	}
	
	/**
	 * Checking if a directory exists.
	 */
	public boolean isExistingDirectory(DBDirectory directory)
	{
		BasicDBObject querryDbObject = new BasicDBObject();
		
		querryDbObject.put("parent", directory.getParentDirectory());
		querryDbObject.put("name", directory.getDirectoryName());
		
		DBObject searchedDirectoryDbObject = MongoDBDAOFactory.dataBase.getCollection(directory.getOwner() + ".directories").findOne(querryDbObject);
		
		if(searchedDirectoryDbObject != null)
		{
			return searchedDirectoryDbObject.containsField("name");
		}
		
		return false;
	}
	
	/**
	 * Checking if existing directory.
	 */
	public boolean isExistingDirectory(String directory, String owner)
	{
		String name = getLastDirectoryInPath(directory);
		String parrent = parentDirectoryFormat(directory);
		
		if(name.equals("") || parrent.equals(""))
		{
			return false;
		}
		
		BasicDBObject querryDbObject = new BasicDBObject();
		
		querryDbObject.put("parent", parrent);
		querryDbObject.put("name", name);
		
		DBObject searchedDirectoryDbObject = MongoDBDAOFactory.dataBase.getCollection(owner + ".directories").findOne(querryDbObject);
		
		if(searchedDirectoryDbObject != null)
		{
			return searchedDirectoryDbObject.containsField("name");
		}
		
		return false;
	}
	
	/**
	 * Getting last directory in the path.
	 * @param path the path.
	 * @return the directory name.
	 */
	private String getLastDirectoryInPath(String path)
	{
		int lastBackSlash = path.lastIndexOf("\\");
		
		if(lastBackSlash == -1)
		{
			return "";
		}
		
		path = path.substring(0, lastBackSlash);
		
		lastBackSlash = path.lastIndexOf("\\");
		
		if(lastBackSlash == -1)
		{
			return "";
		}
		
		return path.substring(lastBackSlash + 1, path.length());
	}
	
	/**
	 * Getting the parrent directory.
	 * @param directory the full directory.
	 * @return the parrent directory.
	 */
	private String parentDirectoryFormat(String directory)
	{
		directory = directory.substring(0, directory.lastIndexOf("\\"));
		
		int lastBackSlash = directory.lastIndexOf("\\");
		
		if(lastBackSlash != -1)
		{
			return directory.substring(0, lastBackSlash + 1);
		}
		else 
		{
			return "";
		}
	}

	/**
	 * Setting the syncronize directory with parameter.
	 */
	public void setSyncDirectory(DBDirectory directory) throws DataBaseErrorException
	{
		try
		{		
			BasicDBObject updateDbObject = new BasicDBObject();
			updateDbObject.put("$set", new BasicDBObject("syncdirparrent", directory.getParentDirectory()).append("syncdirname", directory.getDirectoryName()));
			
			MongoDBDAOFactory.dataBase.getCollection("RegistredUsers").update(new BasicDBObject("UserName", directory.getOwner()), updateDbObject);
		}
		catch (MongoException e) 
		{
			throw new DataBaseErrorException("Error occured on database, when setting the sync directory.");
		}
	}

	/**
	 * Getting the synchronized server directory.
	 */
	public DBDirectory getSyncDirectory(String owner) throws DataBaseErrorException, UserConflictException
	{
		try
		{
			BasicDBObject querryDbObject = new BasicDBObject();
			querryDbObject.put("UserName", owner);
			
			DBObject searchedUserDbObject = MongoDBDAOFactory.dataBase.getCollection("RegistredUsers").findOne(querryDbObject);
			
			if(searchedUserDbObject != null)
			{
				DBDirectory directory = new DBDirectory();
				directory.setDirectoryName((String) searchedUserDbObject.get("syncdirname"));
				directory.setParentDirectory((String) searchedUserDbObject.get("syncdirparrent"));
				directory.setOwner(owner);
				
				return directory;
			}
			else 
			{
				throw new UserConflictException(owner + " not exists in database.");
			}
			
		}
		catch (MongoException e)
		{
			throw new DataBaseErrorException("Error occured on database, when getting the sync directory.");
		}
	}
	
	/**
	 * Getting the default sync directory.
	 */
	public DBDirectory getDefaultSyncDirectory(String owner)
	{
		DBDirectory baseDirectory = new DBDirectory();
		baseDirectory.setOwner(owner);
		baseDirectory.setDirectoryName("sync");
		baseDirectory.setParentDirectory("\\base\\");
		
		return baseDirectory;
	}	
}
